home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Scope / Scope Disk #010 (199x)(Scope PD)(US)[WB].zip / Scope Disk #010 (199x)(Scope PD)(US)[WB].adf / BlitLab3 / blitsim.c < prev    next >
C/C++ Source or Header  |  1988-05-14  |  10KB  |  303 lines

  1. /*
  2.  *   Some code to simulate the blitter!  Original code by Dale Luck
  3.  *   Rewritten by Tomas Rokicki, 12 April 1988.
  4.  */
  5. #include "structures.h"
  6. /*
  7.  *   External values we use.  This is where we get all the parameters
  8.  *   from.  Upper case macros are used to reference this structure
  9.  *   by the names used by the hardware; BLTCON0, for instance, expands
  10.  *   to blitregs.con0.
  11.  */
  12. extern struct blitregs blitregs ;
  13. /*
  14.  *   This routine opens a log file if appropriate.
  15.  */
  16. extern FILE *openlogfile() ;
  17. /*
  18.  *   We use a few macros to make the code easier to understand.
  19.  */
  20. #define BLITTING_FORWARD (!(BLTCON1 & BLITREVERSE))
  21. #define FILL_OK (BLTCON1 & FILL_OR)
  22. #define FILL_XOK (BLTCON1 & FILL_XOR)
  23. #define SRCA_ENABLED (BLTCON0 & SRCA)
  24. #define SRCB_ENABLED (BLTCON0 & SRCB)
  25. #define SRCC_ENABLED (BLTCON0 & SRCC)
  26. #define DEST_ENABLED (BLTCON0 & DEST)
  27. /*
  28.  *   This macro takes two 16-bit words and returns a 32-bit word
  29.  *   formed by concatenating the two words.
  30.  */
  31. #define CATWORDS(a,b) ((((long)(a))<<16)+(unsigned short)(b))
  32. /*
  33.  *   This is the blitter simulator for running the blitter when not
  34.  *   in the line mode.
  35.  */
  36. int donotlineblit() {
  37.    long aptr, bptr, cptr, dptr ;      /* our pointer variables */
  38.    short a_old, b_old ;               /* shifting old values */
  39.    short a_new, b_new ;               /* the input values */
  40.    short a_masked ;                   /* a after masking */
  41.    short a_hold, b_hold, c_hold ;     /* values we build up */
  42.    short h, v ;                       /* indices for iteration */
  43.    short hsize, vsize ;               /* how much to blit */
  44.    short zeroflag ;                   /* see any non-zeros? */
  45.    short amod, bmod, cmod, dmod ;     /* the actual values used */
  46.    short fill_bit ;                   /* for the fill mode */
  47.    short tiny_inc ;                   /* next address (2 or -2) */
  48.    short ashift, bshift ;             /* shift values */
  49.    short minterm ;                    /* the actual function we evaluate */
  50.    short result ;                     /* the value to stuff in d */
  51.    short old_result ;                 /* the blitter is pipelined */
  52.    long old_address ;                 /* where to stuff it */
  53.    short i ;                          /* general purpose iterator */
  54.    FILE *f ;                          /* debug output */
  55.  
  56. /*
  57.  *   Now we initialize our pointer variables, by concatenating the
  58.  *   high and low order words, and clearing the least significant
  59.  *   bit.  The blitter ignores that least significant bit.
  60.  *   Note that the words concatenated in these four statements are
  61.  *   actually adjacent in the actual blitter layout, so they can be
  62.  *   referenced by a single longword read or write.
  63.  */
  64.    aptr = CATWORDS(BLTAPTH,BLTAPTL) & ~1 ;
  65.    bptr = CATWORDS(BLTBPTH,BLTBPTL) & ~1 ;
  66.    cptr = CATWORDS(BLTCPTH,BLTCPTL) & ~1 ;
  67.    dptr = CATWORDS(BLTDPTH,BLTDPTL) & ~1 ;
  68. /*
  69.  *   Our modulos also lose their least significant bit.  Note that
  70.  *   they are treated as signed 16 bit values.
  71.  */
  72.    amod = BLTAMOD & ~1 ;
  73.    bmod = BLTBMOD & ~1 ;
  74.    cmod = BLTCMOD & ~1 ;
  75.    dmod = BLTDMOD & ~1 ;
  76. /*
  77.  *   Next, we extract some information from our control words.
  78.  *   Note that if either the hsize or vsize are zero, their
  79.  *   maximum values are used instead.
  80.  */
  81.    hsize = BLTSIZE & HSIZEMASK ;
  82.    if (hsize == 0)
  83.       hsize = 64 ;
  84.    vsize = (BLTSIZE >> HSIZEBITS) & VSIZEMASK ;
  85.    if (vsize == 0)
  86.       vsize = 1024 ;
  87. /*
  88.  *   We don't want to ever print out more than 32K of debug; there's no
  89.  *   reason, so we turn tracing off if hsize*vsize > 218.
  90.  */
  91.    if (hsize * (long)vsize > 218)
  92.       f = NULL ;
  93.    else
  94.       f = openlogfile() ;
  95.    ashift = (BLTCON0 >> ASHIFTSHIFT) & 0xf ;
  96.    bshift = (BLTCON1 >> BSHIFTSHIFT) & 0xf ;
  97.    minterm = BLTCON0 & 0xff ;
  98. /*
  99.  *   We initialize the zero flag, the old word registers for the
  100.  *   shifters, and get the initial data values for the A, B, and
  101.  *   C channels.
  102.  */
  103.    zeroflag = 0 ;
  104.    a_old = 0 ;
  105.    b_old = 0 ;
  106.    old_address = -1 ;
  107.    a_new = BLTADAT ;
  108.    b_new = BLTBDAT ;
  109.    c_hold = BLTCDAT ;
  110. /*
  111.  *   If we are blitting forward, each time around each DMA channel's
  112.  *   pointer is increased by 2.  Otherwise, it is decremented by 2.
  113.  *   In addition, when blitting backwards, our modulos are subtracted,
  114.  *   so we take care of that by negating them here.
  115.  */
  116.    if (BLITTING_FORWARD) {
  117.       tiny_inc = 2 ;
  118.    } else {
  119.       tiny_inc = -2 ;
  120.       amod = - amod ;
  121.       bmod = - bmod ;
  122.       cmod = - cmod ;
  123.       dmod = - dmod ;
  124.    }
  125. /*
  126.  *   Debug stuff
  127.  */
  128.    if (f) {
  129.       fprintf(f, "\namod = %04x bmod = %04x cmod = %04x dmod = %04x\n",
  130.               amod, bmod, cmod, dmod) ;
  131.       fprintf(f, "adat = %04x bdat = %04x cdat = %04x size = %04x\n",
  132.               a_new, b_new, c_hold, BLTSIZE) ;
  133.       fprintf(f, "con0 = %04x con1 = %04x afwm = %04x alwm = %04x\n",
  134.               BLTCON0, BLTCON1, BLTAFWM, BLTALWM) ;
  135.       logflagdata(f) ;
  136.    }
  137. /*
  138.  *   We iterate through the rows, and print debug stuff each time.
  139.  */
  140.    for (v=0; v<vsize; v++) {
  141.       if (f)
  142.          fprintf(f, ">>>Row %d\n", v) ;
  143. /*
  144.  *   At the beginning of each row, the fill bit gets set to its initial
  145.  *   value from the control register.
  146.  */
  147.       fill_bit = (BLTCON1 & FILL_CARRYIN ? 0xffff : 0) ;
  148. /*
  149.  *   Now we run through the columns, again printing debug information
  150.  *   each time around.
  151.  */
  152.       for (h=0; h<hsize; h++) {
  153.          if (f)
  154.             fprintf(f, "aptr = %08lx bptr = %08lx cptr = %08lx dptr = %08lx\n",
  155.                     aptr, bptr, cptr, dptr) ;
  156. /*
  157.  *   For each of the three sources, we fetch values if they are
  158.  *   enabled, and then increment (or decrement) the pointers.
  159.  *   I'm not sure if the pointers are actually incremented or not
  160.  *   if the DMA channels are turned off.
  161.  */
  162.          if (SRCA_ENABLED)
  163.             a_new = *(short *)aptr ;
  164.          aptr += tiny_inc ;
  165.          if (SRCB_ENABLED)
  166.             b_new = *(short *)bptr ;
  167.          bptr += tiny_inc ;
  168.          if (SRCC_ENABLED)
  169.             c_hold = *(short *)cptr ;
  170.          cptr += tiny_inc ;
  171. /*
  172.  *   Debug stuff
  173.  */
  174.          if (f)
  175.             fprintf(f, "adat = %04x bdat = %04x cdat = %04x\n",
  176.                     a_new, b_new, c_hold) ;
  177. /*
  178.  *   If we are at the first word on a line, we mask with afwm.
  179.  *   If we are at the last, we mask with alwm.  Note that if the
  180.  *   width is 1, both masks are used.
  181.  */
  182.          a_masked = a_new ;
  183.          if (h == 0)
  184.             a_masked &= BLTAFWM ;
  185.          if (h == hsize - 1)
  186.             a_masked &= BLTALWM ;
  187. /*
  188.  *   Now we concatenate our old values with the new values and shift
  189.  *   them the appropriate amounts to determine the actual values as
  190.  *   input to our function generator.  Note that in decrement mode, the
  191.  *   shifts are backwards.  Then, we save the old values for the next
  192.  *   time around.
  193.  */
  194.          if (BLITTING_FORWARD) {
  195.             a_hold = CATWORDS(a_old,a_masked) >> ashift ;
  196.             b_hold = CATWORDS(b_old,b_new) >> bshift ;
  197.          } else {
  198.             a_hold = CATWORDS(a_masked,a_old) >> (16 - ashift) ;
  199.             b_hold = CATWORDS(b_new,b_old) >> (16 - bshift) ;
  200.          }
  201.          a_old = a_masked ;
  202.          b_old = b_new ;
  203. /*
  204.  *   Our minterm calculation is next.
  205.  */
  206.          result = (minterm & 1 ? ~a_hold & ~b_hold & ~c_hold : 0)
  207.                  | (minterm & 2 ? ~a_hold & ~b_hold & c_hold : 0)
  208.                  | (minterm & 4 ? ~a_hold & b_hold & ~c_hold : 0)
  209.                  | (minterm & 8 ? ~a_hold & b_hold & c_hold : 0)
  210.                  | (minterm & 16 ? a_hold & ~b_hold & ~c_hold : 0)
  211.                  | (minterm & 32 ? a_hold & ~b_hold & c_hold : 0)
  212.                  | (minterm & 64 ? a_hold & b_hold & ~c_hold : 0)
  213.                  | (minterm & 128 ? a_hold & b_hold & c_hold : 0) ;
  214. /*
  215.  *   If we are in the fill mode, we do the appropriate thing.  Note that
  216.  *   fill only works properly when in the descending mode.  FILL_XOK
  217.  *   turns off bits which toggle fill_bit to zero.
  218.  */
  219.          if (FILL_OK || FILL_XOK)
  220.             for (i=1; i; i <<= 1)
  221.                if (result & i) {
  222.                   if (FILL_XOK && fill_bit)
  223.                      result &= ~i ;
  224.                   fill_bit = ~fill_bit ;
  225.                } else
  226.                   result |= (i & fill_bit) ;
  227. /*
  228.  *   Debug stuff.
  229.  */
  230.          if (f)
  231.             fprintf(f, "aval = %04x bval = %04x cval = %04x dval = %04x\n",
  232.                     a_hold, b_hold, c_hold, result) ;
  233. /*
  234.  *   We or in our result to our zero flag; this way, if we ever hit a zero
  235.  *   result, zeroflag will be non-zero.
  236.  */
  237.          zeroflag |= result ;
  238. /*
  239.  *   The actual writing is pipelined one stage; if we buffered a write
  240.  *   last time around, we write it here.
  241.  */
  242.          if (old_address != -1) {
  243.             if (f)
  244.                fprintf(f, "***  [%08lx] <-- %04x\n", old_address, old_result) ;
  245.             screenupdate(old_address, old_result) ;
  246.          }
  247. /*
  248.  *   If the destination is enabled, we buffer up a value to be written the
  249.  *   next time around.  Again, the pointer might not really be incremented
  250.  *   if the destination is disabled.
  251.  */
  252.          if (DEST_ENABLED) {
  253.             old_result = result ;
  254.             old_address = dptr ;
  255.          }
  256.          dptr += tiny_inc ;
  257.       }
  258. /*
  259.  *   Next, we add the modulos to all the pointers at the end of each row.
  260.  */
  261.       aptr += amod ;
  262.       bptr += bmod ;
  263.       cptr += cmod ;
  264.       dptr += dmod ;
  265.    }
  266. /*
  267.  *   Finally, we are at the end of the blit; if we still have a write in
  268.  *   the pipeline, we write it here.
  269.  */
  270.    if (old_address != -1) {
  271.       if (f)
  272.          fprintf(f, "***  [%08lx] <-- %04x\n", old_address, old_result) ;
  273.       screenupdate(old_address, old_result) ;
  274.    }
  275.    if (f)
  276.       fclose(f) ;
  277. /*
  278.  *   If we ever saw a non-zero value, then zeroflag is set, so we return
  279.  *   a zero; otherwise, we return a 1.
  280.  */
  281.    return(!zeroflag) ;
  282. }
  283. /*
  284.  *   And this is the simulator for when we are in the line mode.
  285.  *   (Oh, shucks, you mean it's not written yet?)
  286.  */
  287. int dolineblit() {
  288.    error("we can't simulate line blits yet.") ;
  289.    Delay(50L) ;
  290.    return(0) ;
  291. }
  292. /*
  293.  *   The actual routine.  All we do is call the appropriate real
  294.  *   routine, depending on whether the line mode is set or not.
  295.  */
  296. int dosimblit() {
  297.    error("Simulating . . .") ;
  298.    if (BLTCON1 & LINEMODE)
  299.       return(dolineblit()) ;
  300.    else
  301.       return(donotlineblit()) ;
  302. }
  303.